﻿/**********************************************************
 ●项目：Smartkernel
 ●公司：智能核心信息技术研发中心
 ●作者：曹艳白
 ●邮箱：caoyanbai@gmail.com
 ●创建：2008-08-10
**********************************************************/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Smartkernel.Caching;
using Smartkernel.Exceptions;
using Smartkernel.Resource;

namespace Smartkernel
{
    /// <summary>
    /// 智能数学类，提供数学相关的操作
    /// </summary>
    public static partial class SmartMath
    {
        #region 公有方法
        /// <summary>
        /// 动态计算表达式的值，通过动态生成一个类来实现
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <param name="isCache">是否缓存结果，如果缓存，则只在第一次调用时动态生成类进行计算</param>
        /// <returns>返回的值</returns>
        public static object DynamicEval(string expression, bool isCache)
        {
            object result = null;
            if (isCache)
            {
                string key = expression.GetHashCode().ToString();
                string category = "__SmartMath__DynamicEvalCategory";
                if (SmartMemoryCacher.ContainsKey(category, key))
                {
                    result = SmartMemoryCacher.GetValue(category, key);
                }
                else
                {
                    result = DynamicEval(expression);
                    SmartMemoryCacher.Add(category, key, result);
                }
            }
            else
            {
                result = DynamicEval(expression);
            }
            return result;
        }
        /// <summary>
        /// 计算表达式（将表达式转换为后缀表达式之后进行计算的算法实现）
        /// </summary>
        /// <param name="expression">表达式，表达式符号之间必须使用空格分隔</param>
        /// <returns>计算的结果</returns>
        public static double Eval(string expression)
        {
            expression = ChangeFromInfixToPostfix(expression);
            Stack<string> stack = new Stack<string>();
            string[] tokens = expression.Trim().Split(' ');
            double result = 0;
            double right = 0;
            double left = 0;
            for (int i = 0; i < tokens.Length; i++)
            {
                string token = tokens[i].ToString();
                switch (token)
                {
                    case "+":
                        right = Convert.ToDouble(stack.Pop());
                        left = Convert.ToDouble(stack.Pop());
                        result = left + right;
                        stack.Push(result.ToString());
                        break;
                    case "-":
                        right = Convert.ToDouble(stack.Pop());
                        left = Convert.ToDouble(stack.Pop());
                        result = left - right;
                        stack.Push(result.ToString());
                        break;
                    case "*":
                        right = Convert.ToDouble(stack.Pop());
                        left = Convert.ToDouble(stack.Pop());
                        result = left * right;
                        stack.Push(result.ToString());
                        break;
                    case "/":
                        right = Convert.ToDouble(stack.Pop());
                        left = Convert.ToDouble(stack.Pop());
                        result = left / right;
                        stack.Push(result.ToString());
                        break;
                    default:
                        stack.Push(token);
                        break;
                }
            }
            return result;
        }
        /// <summary>
        /// 二进制转换为十进制
        /// </summary>
        /// <param name="input">待转换的字符串</param>
        /// <returns>转换的结果</returns>
        public static int BinaryToDecimal(string input)
        {
            return Convert.ToInt32(input, 2);
        }
        /// <summary>
        /// 八进制转换为十进制
        /// </summary>
        /// <param name="input">待转换的字符串</param>
        /// <returns>转换的结果</returns>
        public static int OctalToDecimal(string input)
        {
            return Convert.ToInt32(input, 8);
        }
        /// <summary>
        /// 十六进制转换为十进制
        /// </summary>
        /// <param name="input">待转换的字符串</param>
        /// <returns>转换的结果</returns>
        public static int HexToDecimal(string input)
        {
            return Convert.ToInt32(input, 16);
        }
        /// <summary>
        /// 十进制转换为二进制
        /// </summary>
        /// <param name="input">待转换的数字</param>
        /// <returns>转换的结果</returns>
        public static string DecimalToBinary(int input)
        {
            return Convert.ToString(input, 2);
        }
        /// <summary>
        /// 十进制转换为八进制
        /// </summary>
        /// <param name="input">待转换的数字</param>
        /// <returns>转换的结果</returns>
        public static string DecimalToOctal(int input)
        {
            return Convert.ToString(input, 8);
        }
        /// <summary>
        /// 十进制转换为十六进制
        /// </summary>
        /// <param name="input">待转换的数字</param>
        /// <returns>转换的结果</returns>
        public static string ToDecimalHex(int input)
        {
            return Convert.ToString(input, 16);
        }
        /// <summary>
        /// 角度转换为弧度
        /// </summary>
        /// <param name="input">待转换的角度值</param>
        /// <returns>弧度表示</returns>
        public static double AngleToRadian(double input)
        {
            return (Math.PI * input) / 180d;
        }
        #endregion
    }
    public static partial class SmartMath
    {
        #region 私有方法
        /// <summary>
        /// 动态计算表达式的值，通过动态生成一个类来实现
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <returns>返回的值</returns>
        private static object DynamicEval(string expression)
        {
            string[] referencedAssemblies = { "system.dll" };

            string className = "__DynamicClass_SmartMath_Eval_" + expression.GetHashCode().ToString().Replace("-", "_");
            string namespaceName = "Smartkernel";
            StringBuilder code = new StringBuilder();
            code.Append("using System;");
            code.Append("namespace " + namespaceName);
            code.Append("{");
            code.Append("public class " + className);
            code.Append("{");
            code.Append("public object Eval()");
            code.Append("{");
            code.Append("return " + expression + ";");
            code.Append("}");
            code.Append("}");
            code.Append("}");

            Assembly assembly = SmartCodeCompiler.Compile(referencedAssemblies, code.ToString(), false);
            object obj = assembly.CreateInstance(namespaceName + "." + className);

            return SmartReflection.MethodInvoke("Eval", obj);
        }
        /// <summary>
        /// 中缀表达式转后缀表达式
        /// </summary>
        /// <param name="expression">表达式，注意表达式必须用空格分割符号</param>
        /// <returns>后缀表达式</returns>
        private static string ChangeFromInfixToPostfix(string expression)
        {
            //符号数组
            string[] tokens = expression.Split(' ');
            if (tokens.Length < 3)
            {
                throw new SmartException(SmartExceptionMessageResource.SmartMath_ChangeFromInfixToPostfix_expressionNotInfix);
            }
            //保存处理结果的栈
            Stack<string> stack = new Stack<string>();
            //处理的结果（后缀表达式）
            string result = "";
            //空格
            string blank = " ";
            for (int i = 0; i < tokens.Length; i++)
            {
                string token = tokens[i].ToString();
                switch (token)
                {
                    case "(":
                        stack.Push(token);
                        break;
                    case ")":
                        while (true)
                        {
                            string topToken = stack.Pop();
                            if (topToken == "(")
                            {
                                break;
                            }
                            result = result + blank + topToken;
                        }
                        break;
                    case "+":
                    case "-":
                    case "*":
                    case "/":
                        while (true)
                        {
                            if (stack.Count == 0 || stack.Peek() == "(" || (token == "*" || token == "/") && (stack.Peek() == "+" || stack.Peek() == "-"))
                            {
                                stack.Push(token);
                                break;
                            }
                            else
                            {
                                result = result + blank + stack.Pop();
                            }
                        }
                        break;
                    default:
                        result = result + blank + token;
                        break;
                }
            }
            while (true)
            {
                if (stack.Count == 0)
                {
                    break;
                }
                string topToken = stack.Pop();
                if (topToken != "(")
                {
                    result = result + blank + topToken;
                }
                else
                {
                    throw new SmartException(SmartExceptionMessageResource.SmartMath_ChangeFromInfixToPostfix_expressionNotInfix);
                }
            }
            return result;
        }
        #endregion
    }
}